/**
 * 位置服务模块
 * 提供跨平台的位置获取功能，增强H5环境下的位置获取成功率
 */

// 状态码定义
export const LOCATION_STATUS = {
  SUCCESS: 0,              // 成功获取位置
  PERMISSION_DENIED: 1,    // 权限被拒绝
  POSITION_UNAVAILABLE: 2, // 位置信息不可用
  TIMEOUT: 3,              // 获取超时
  UNSUPPORTED: 4,          // 不支持定位功能
  UNKNOWN_ERROR: 5         // 未知错误
};

/**
 * 检查是否已开启HTTPS
 * Geolocation API在现代浏览器中要求必须使用HTTPS
 */
function isSecureContext() {
  return window.isSecureContext === true || location.protocol === 'https:';
}

/**
 * 检查H5浏览器是否支持地理定位
 */
export function isSupportGeolocation() {
  // #ifndef H5
  return true;
  // #endif
  
  // #ifdef H5
  return navigator && navigator.geolocation;
  // #endif
}

/**
 * 获取当前位置
 * @param {Object} options 配置选项
 * @param {Boolean} options.enableHighAccuracy 是否启用高精度 默认true
 * @param {Number} options.timeout 超时时间(毫秒) 默认10000
 * @param {Number} options.maximumAge 位置缓存有效期(毫秒) 默认0
 * @param {Boolean} options.autoShowPermissionGuide 自动显示权限引导 默认true
 * @returns {Promise} 返回包含位置信息的Promise
 */
export function getLocation(options = {}) {
  return new Promise((resolve, reject) => {
    // 合并默认选项
    const defaultOptions = {
      enableHighAccuracy: true,
      timeout: 10000,
      maximumAge: 0,
      autoShowPermissionGuide: true,
      type: 'gcj02' // uni-app位置坐标系
    };
    
    const mergedOptions = {...defaultOptions, ...options};
    
    // #ifdef APP-PLUS || MP-WEIXIN
    // 小程序和APP环境下使用uni-app的API
    uni.getLocation({
      type: mergedOptions.type,
      geocode: mergedOptions.geocode || false,
      altitude: mergedOptions.altitude || false,
      highAccuracyExpireTime: mergedOptions.highAccuracyExpireTime,
      isHighAccuracy: mergedOptions.enableHighAccuracy,
      success: (res) => {
        console.log('获取位置成功:', res);
        resolve({
          status: LOCATION_STATUS.SUCCESS,
          message: '获取位置成功',
          data: res
        });
      },
      fail: (err) => {
        console.error('获取位置失败:', err);
        
        let status = LOCATION_STATUS.UNKNOWN_ERROR;
        let message = '获取位置失败';
        
        if (err.errMsg) {
          if (err.errMsg.indexOf('auth deny') !== -1 || err.errMsg.indexOf('permission denied') !== -1) {
            status = LOCATION_STATUS.PERMISSION_DENIED;
            message = '位置权限被拒绝';
            
            // 自动显示权限引导
            if (mergedOptions.autoShowPermissionGuide) {
              showPermissionGuideInMiniAppOrApp();
            }
          } else if (err.errMsg.indexOf('system error') !== -1) {
            status = LOCATION_STATUS.POSITION_UNAVAILABLE;
            message = '系统错误，请检查位置服务是否开启';
          } else if (err.errMsg.indexOf('timeout') !== -1) {
            status = LOCATION_STATUS.TIMEOUT;
            message = '获取位置超时，请检查网络';
          }
        }
        
        reject({
          status,
          message,
          original: err
        });
      }
    });
    // #endif
    
    // #ifdef H5
    // H5环境下使用Web API
    if (!navigator.geolocation) {
      // 浏览器不支持地理定位
      console.error('当前浏览器不支持Geolocation API');
      
      reject({
        status: LOCATION_STATUS.UNSUPPORTED,
        message: '当前浏览器不支持位置获取功能'
      });
      
      // 显示不支持提示
      if (mergedOptions.autoShowPermissionGuide) {
        showUnsupportedGuide();
      }
      
      return;
    }
    
    // 检查是否在安全上下文中
    if (!isSecureContext()) {
      // 非HTTPS环境下提示使用HTTPS
      console.warn('非HTTPS环境可能无法正常获取位置，建议切换到HTTPS');
      
      // 可以继续尝试获取位置，但大多数浏览器会阻止
      if (mergedOptions.autoShowPermissionGuide) {
        showHttpsRequiredGuide();
      }
    }
    
    // 尝试获取位置
    navigator.geolocation.getCurrentPosition(
      // 成功回调
      (position) => {
        console.log('H5环境获取位置成功:', position);
        
        // 构建与uni-app接口一致的返回格式
        const result = {
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          accuracy: position.coords.accuracy,
          altitude: position.coords.altitude,
          verticalAccuracy: position.coords.altitudeAccuracy,
          horizontalAccuracy: position.coords.accuracy,
          speed: position.coords.speed,
          direction: position.coords.heading,
          timestamp: position.timestamp
        };
        
        resolve({
          status: LOCATION_STATUS.SUCCESS,
          message: '获取位置成功',
          data: result
        });
      },
      // 错误回调
      (error) => {
        console.error('H5环境获取位置失败:', error);
        
        let status = LOCATION_STATUS.UNKNOWN_ERROR;
        let message = '获取位置失败';
        
        // 根据错误代码给出更具体的错误信息
        switch(error.code) {
          case error.PERMISSION_DENIED:
            status = LOCATION_STATUS.PERMISSION_DENIED;
            message = '位置权限被拒绝';
            
            // 自动显示权限引导
            if (mergedOptions.autoShowPermissionGuide) {
              showPermissionGuideInH5();
            }
            break;
          case error.POSITION_UNAVAILABLE:
            status = LOCATION_STATUS.POSITION_UNAVAILABLE;
            message = '位置信息不可用';
            break;
          case error.TIMEOUT:
            status = LOCATION_STATUS.TIMEOUT;
            message = '获取位置超时';
            break;
        }
        
        reject({
          status,
          message,
          original: error
        });
      },
      // 选项
      {
        enableHighAccuracy: mergedOptions.enableHighAccuracy,
        timeout: mergedOptions.timeout,
        maximumAge: mergedOptions.maximumAge
      }
    );
    // #endif
  });
}

/**
 * 在H5环境下显示权限引导
 * 帮助用户开启位置权限
 */
function showPermissionGuideInH5() {
  const hasShown = uni.getStorageSync('has_shown_location_guide');
  
  // 避免频繁显示引导
  if (hasShown) {
    const lastTime = parseInt(hasShown);
    const now = Date.now();
    
    // 1小时内不重复显示
    if (now - lastTime < 3600000) {
      return;
    }
  }
  
  // 记录显示时间
  uni.setStorageSync('has_shown_location_guide', Date.now().toString());
  
  // 获取浏览器信息
  let browserTips = '';
  const userAgent = navigator.userAgent.toLowerCase();
  
  if (userAgent.indexOf('micromessenger') > -1) {
    // 微信内置浏览器
    browserTips = '1. 点击右上角"..."按钮\n2. 选择"设置"\n3. 找到"位置信息"并开启';
  } else if (userAgent.indexOf('chrome') > -1) {
    // Chrome浏览器
    browserTips = '1. 点击地址栏左侧的锁形/感叹号图标\n2. 找到"位置"选项\n3. 选择"允许"';
  } else if (userAgent.indexOf('safari') > -1 && userAgent.indexOf('chrome') === -1) {
    // Safari浏览器
    browserTips = '1. 打开"设置" > "Safari"\n2. 找到"位置服务"\n3. 允许位置权限';
  } else if (userAgent.indexOf('firefox') > -1) {
    // Firefox浏览器
    browserTips = '1. 点击地址栏左侧的锁形/感叹号图标\n2. 找到"位置访问权限"\n3. 选择"允许"';
  } else {
    // 其他浏览器
    browserTips = '1. 点击浏览器地址栏左侧的锁形/感叹号图标\n2. 在弹出的权限设置中，允许位置访问';
  }
  
  uni.showModal({
    title: '需要位置权限',
    content: `请允许获取您的位置信息以提供更好的服务体验。\n\n${browserTips}\n\n4. 刷新页面后重试`,
    confirmText: '我知道了',
    showCancel: false,
    success: () => {
      // 用户确认后，尝试刷新页面
      setTimeout(() => {
        uni.showToast({
          title: '请刷新页面重试',
          icon: 'none',
          duration: 3000
        });
      }, 500);
    }
  });
}

/**
 * 显示小程序或APP环境下的权限引导
 */
function showPermissionGuideInMiniAppOrApp() {
  // #ifdef MP-WEIXIN
  uni.showModal({
    title: '需要位置权限',
    content: '请允许小程序获取您的位置信息以提供更好的服务体验',
    confirmText: '去授权',
    cancelText: '取消',
    success: (res) => {
      if (res.confirm) {
        uni.openSetting({
          success: (settingRes) => {
            console.log('打开设置页面成功', settingRes);
          }
        });
      }
    }
  });
  // #endif
  
  // #ifdef APP-PLUS
  uni.showModal({
    title: '需要位置权限',
    content: '请允许应用获取您的位置信息以提供更好的服务体验',
    confirmText: '去设置',
    cancelText: '取消',
    success: (res) => {
      if (res.confirm) {
        if (plus.os.name.toLowerCase() === 'android') {
          // Android设备
          const Intent = plus.android.importClass('android.content.Intent');
          const Settings = plus.android.importClass('android.provider.Settings');
          const Uri = plus.android.importClass('android.net.Uri');
          const mainActivity = plus.android.runtimeMainActivity();
          const intent = new Intent();
          intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
          const uri = Uri.fromParts('package', mainActivity.getPackageName(), null);
          intent.setData(uri);
          mainActivity.startActivity(intent);
        } else if (plus.os.name.toLowerCase() === 'ios') {
          // iOS设备
          plus.runtime.openURL('app-settings:');
        }
      }
    }
  });
  // #endif
}

/**
 * 显示浏览器不支持地理定位的提示
 */
function showUnsupportedGuide() {
  uni.showModal({
    title: '浏览器不支持位置获取',
    content: '您的浏览器不支持位置获取功能。请尝试使用更现代的浏览器（如Chrome、Firefox、Safari等），或检查浏览器设置是否禁用了位置功能。',
    confirmText: '我知道了',
    showCancel: false
  });
}

/**
 * 显示需要HTTPS环境的提示
 */
function showHttpsRequiredGuide() {
  uni.showModal({
    title: '需要安全连接',
    content: '获取位置需要在HTTPS安全连接下使用。请使用HTTPS访问本网站，或联系网站管理员启用HTTPS。',
    confirmText: '我知道了',
    showCancel: false
  });
}

/**
 * 指引用户开启设备位置服务
 * 适用于位置服务未开启的情况
 */
export function showLocationServiceGuide() {
  // #ifdef APP-PLUS
  let content = '';
  
  if (plus.os.name.toLowerCase() === 'android') {
    content = '请前往设备"设置">"位置信息"中开启位置服务';
  } else if (plus.os.name.toLowerCase() === 'ios') {
    content = '请前往设备"设置">"隐私">"定位服务"中开启位置服务';
  }
  
  uni.showModal({
    title: '位置服务未开启',
    content,
    confirmText: '去设置',
    cancelText: '取消',
    success: (res) => {
      if (res.confirm) {
        if (plus.os.name.toLowerCase() === 'android') {
          const Intent = plus.android.importClass('android.content.Intent');
          const Settings = plus.android.importClass('android.provider.Settings');
          const mainActivity = plus.android.runtimeMainActivity();
          const intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
          mainActivity.startActivity(intent);
        } else if (plus.os.name.toLowerCase() === 'ios') {
          plus.runtime.openURL('app-settings:');
        }
      }
    }
  });
  // #endif
  
  // #ifdef MP-WEIXIN || H5
  uni.showModal({
    title: '位置服务未开启',
    content: '请在设备设置中开启位置服务后重试',
    confirmText: '我知道了',
    showCancel: false
  });
  // #endif
}

/**
 * 持续监听位置变化
 * @param {Function} successCallback 成功回调
 * @param {Function} errorCallback 错误回调
 * @param {Object} options 配置选项
 * @returns {Object} 定位监听器，包含stop方法停止监听
 */
export function watchLocation(successCallback, errorCallback, options = {}) {
  // 合并默认选项
  const mergedOptions = {
    enableHighAccuracy: true,
    timeout: 10000,
    maximumAge: 0,
    ...options
  };
  
  let watchId = null;
  
  // #ifdef H5
  if (navigator.geolocation) {
    watchId = navigator.geolocation.watchPosition(
      // 成功回调
      (position) => {
        const result = {
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          accuracy: position.coords.accuracy,
          altitude: position.coords.altitude,
          verticalAccuracy: position.coords.altitudeAccuracy,
          horizontalAccuracy: position.coords.accuracy,
          speed: position.coords.speed,
          direction: position.coords.heading,
          timestamp: position.timestamp
        };
        
        successCallback && successCallback({
          status: LOCATION_STATUS.SUCCESS,
          message: '获取位置成功',
          data: result
        });
      },
      // 错误回调
      (error) => {
        let status = LOCATION_STATUS.UNKNOWN_ERROR;
        let message = '获取位置失败';
        
        switch(error.code) {
          case error.PERMISSION_DENIED:
            status = LOCATION_STATUS.PERMISSION_DENIED;
            message = '位置权限被拒绝';
            break;
          case error.POSITION_UNAVAILABLE:
            status = LOCATION_STATUS.POSITION_UNAVAILABLE;
            message = '位置信息不可用';
            break;
          case error.TIMEOUT:
            status = LOCATION_STATUS.TIMEOUT;
            message = '获取位置超时';
            break;
        }
        
        errorCallback && errorCallback({
          status,
          message,
          original: error
        });
      },
      // 选项
      {
        enableHighAccuracy: mergedOptions.enableHighAccuracy,
        timeout: mergedOptions.timeout,
        maximumAge: mergedOptions.maximumAge
      }
    );
  } else {
    errorCallback && errorCallback({
      status: LOCATION_STATUS.UNSUPPORTED,
      message: '当前浏览器不支持位置获取功能'
    });
  }
  // #endif
  
  // #ifdef APP-PLUS
  // App环境下使用plus.geolocation.watchPosition
  if (plus.geolocation) {
    watchId = plus.geolocation.watchPosition(
      (position) => {
        const result = {
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          accuracy: position.coords.accuracy,
          altitude: position.coords.altitude,
          altitudeAccuracy: position.coords.altitudeAccuracy,
          heading: position.coords.heading,
          speed: position.coords.speed,
          timestamp: position.timestamp
        };
        
        successCallback && successCallback({
          status: LOCATION_STATUS.SUCCESS,
          message: '获取位置成功',
          data: result
        });
      },
      (error) => {
        errorCallback && errorCallback({
          status: LOCATION_STATUS.UNKNOWN_ERROR,
          message: error.message || '获取位置失败',
          original: error
        });
      },
      {
        enableHighAccuracy: mergedOptions.enableHighAccuracy,
        timeout: mergedOptions.timeout,
        maximumAge: mergedOptions.maximumAge
      }
    );
  }
  // #endif
  
  // 返回监听器对象，提供停止监听的方法
  return {
    /**
     * 停止位置监听
     */
    stop: () => {
      // #ifdef H5
      if (navigator.geolocation && watchId !== null) {
        navigator.geolocation.clearWatch(watchId);
        watchId = null;
      }
      // #endif
      
      // #ifdef APP-PLUS
      if (plus.geolocation && watchId !== null) {
        plus.geolocation.clearWatch(watchId);
        watchId = null;
      }
      // #endif
    }
  };
}

/**
 * 一次性获取位置并进行反向地址解析
 * @param {Object} options 配置选项
 * @returns {Promise} 包含位置和地址信息的Promise
 */
export function getLocationWithAddress(options = {}) {
  return new Promise((resolve, reject) => {
    // 先获取位置
    getLocation({...options, geocode: true})
      .then(res => {
        // 如果uni-app已经返回了地址信息
        if (res.data.address) {
          resolve(res);
          return;
        }
        
        // 需要额外进行反向地址解析
        const latitude = res.data.latitude;
        const longitude = res.data.longitude;
        
        // 使用腾讯地图进行反向地址解析
        uni.request({
          url: 'https://apis.map.qq.com/ws/geocoder/v1/',
          data: {
            location: `${latitude},${longitude}`,
            key: options.mapKey || 'JMRBZ-R6JCU-RTJVI-4FICN-T53O3-KUFZS', // 使用传入的key或默认key
            get_poi: 0
          },
          success: (addressRes) => {
            if (addressRes.data && addressRes.data.status === 0 && addressRes.data.result) {
              // 合并位置和地址信息
              const result = {
                ...res,
                address: {
                  ...addressRes.data.result
                }
              };
              
              resolve(result);
            } else {
              // 地址解析失败，仍然返回位置信息
              resolve(res);
            }
          },
          fail: () => {
            // 地址解析请求失败，仍然返回位置信息
            resolve(res);
          }
        });
      })
      .catch(err => {
        reject(err);
      });
  });
}

/**
 * 尝试使用IP定位作为后备方案
 * 当浏览器定位失败时使用
 * @returns {Promise} 返回位置信息
 */
export function getLocationByIP() {
  return new Promise((resolve, reject) => {
    console.log('[IP定位] 尝试使用腾讯地图IP定位服务');
    
    // 尝试请求前先检查网络连接
    if (!navigator.onLine) {
      console.error('[IP定位] 网络连接不可用');
      reject({
        status: LOCATION_STATUS.UNKNOWN_ERROR,
        message: '网络连接不可用，无法获取IP位置',
        original: { error: 'NETWORK_UNAVAILABLE' }
      });
      return;
    }
    
    // 增加超时处理
    const timeoutPromise = new Promise((_, timeoutReject) => {
      setTimeout(() => {
        timeoutReject({
          status: LOCATION_STATUS.TIMEOUT,
          message: 'IP定位请求超时',
          original: { error: 'TIMEOUT' }
        });
      }, 10000); // 10秒超时
    });
    
    // 主IP定位请求
    const ipLocatePromise = new Promise((ipResolve, ipReject) => {
      uni.request({
        url: 'https://apis.map.qq.com/ws/location/v1/ip',
        data: {
          key: 'JMRBZ-R6JCU-RTJVI-4FICN-T53O3-KUFZS', // 腾讯地图key
          output: 'json'
        },
        success: (res) => {
          console.log('[IP定位] 腾讯地图返回:', res);
          
          if (res.data && res.data.status === 0 && res.data.result) {
            const result = res.data.result;
            
            // 构建与getLocation返回格式一致的结果
            ipResolve({
              status: LOCATION_STATUS.SUCCESS,
              message: '通过IP获取位置成功(精确度较低)',
              data: {
                latitude: result.location.lat,
                longitude: result.location.lng,
                accuracy: 5000, // IP定位精度很低，大约5公里
                address: result.ad_info.nation + result.ad_info.province + result.ad_info.city + result.ad_info.district,
                nation: result.ad_info.nation,
                province: result.ad_info.province,
                city: result.ad_info.city,
                district: result.ad_info.district,
                _ip_location: true, // 标记这是IP定位
                _provider: 'tencent' // 标记数据提供商
              }
            });
          } else {
            ipReject({
              status: LOCATION_STATUS.UNKNOWN_ERROR,
              message: '通过IP获取位置失败',
              original: res.data
            });
          }
        },
        fail: (err) => {
          console.error('[IP定位] 腾讯地图请求失败:', err);
          ipReject({
            status: LOCATION_STATUS.UNKNOWN_ERROR,
            message: '通过IP获取位置请求失败',
            original: err
          });
        }
      });
    });
    
    // 使用Promise.race处理超时
    Promise.race([ipLocatePromise, timeoutPromise])
      .then(result => {
        resolve(result);
      })
      .catch(error => {
        console.warn('[IP定位] 腾讯地图IP定位失败，尝试备用方案');
        // 如果失败，尝试备选的IP定位服务
        tryBackupIPLocation(resolve, reject);
      });
  });
}

/**
 * 备用IP定位服务
 * 使用公共免费API作为备选
 * @param {Function} resolve Promise解析函数
 * @param {Function} reject Promise拒绝函数
 */
function tryBackupIPLocation(resolve, reject) {
  console.log('[IP定位] 尝试备选IP定位服务');
  
  // 首先尝试ipapi.co服务
  uni.request({
    url: 'https://ipapi.co/json/',
    success: (res) => {
      console.log('[IP定位] ipapi.co返回:', res);
      
      if (res.data && res.data.latitude && res.data.longitude) {
        // 构建与getLocation返回格式一致的结果
        resolve({
          status: LOCATION_STATUS.SUCCESS,
          message: '通过备选IP定位服务获取位置成功(精确度较低)',
          data: {
            latitude: res.data.latitude,
            longitude: res.data.longitude,
            accuracy: 10000, // 备选服务精度更低
            address: `${res.data.country_name} ${res.data.region} ${res.data.city}`,
            nation: res.data.country_name,
            province: res.data.region,
            city: res.data.city,
            _ip_location: true, // 标记这是IP定位
            _provider: 'ipapi.co' // 标记数据提供商
          }
        });
      } else {
        console.warn('[IP定位] ipapi.co服务返回数据无效，尝试最后的备选方案');
        // 如果第一个备选也失败，尝试第二个备选
        tryLastBackupIPLocation(resolve, reject);
      }
    },
    fail: (err) => {
      console.error('[IP定位] ipapi.co请求失败:', err);
      // 尝试最后的备选服务
      tryLastBackupIPLocation(resolve, reject);
    }
  });
}

/**
 * 最后的备用IP定位服务
 * 使用另一个免费API作为最后的备选
 * @param {Function} resolve Promise解析函数
 * @param {Function} reject Promise拒绝函数
 */
function tryLastBackupIPLocation(resolve, reject) {
  console.log('[IP定位] 尝试最后的备选IP定位服务');
  
  // 尝试ip-api.com服务
  uni.request({
    url: 'http://ip-api.com/json/?fields=status,country,regionName,city,lat,lon,query',
    success: (res) => {
      console.log('[IP定位] ip-api.com返回:', res);
      
      if (res.data && res.data.status === 'success' && res.data.lat && res.data.lon) {
        // 构建与getLocation返回格式一致的结果
        resolve({
          status: LOCATION_STATUS.SUCCESS,
          message: '通过最后备选IP定位服务获取位置成功(精确度较低)',
          data: {
            latitude: res.data.lat,
            longitude: res.data.lon,
            accuracy: 15000, // 最后备选精度最低
            address: `${res.data.country} ${res.data.regionName} ${res.data.city}`,
            nation: res.data.country,
            province: res.data.regionName,
            city: res.data.city,
            _ip_location: true, // 标记这是IP定位
            _provider: 'ip-api.com' // 标记数据提供商
          }
        });
      } else {
        // 所有服务都失败
        reject({
          status: LOCATION_STATUS.UNKNOWN_ERROR,
          message: '所有IP定位服务均失败',
          original: { error: 'ALL_SERVICES_FAILED' }
        });
      }
    },
    fail: (err) => {
      console.error('[IP定位] ip-api.com请求失败:', err);
      // 所有服务都失败
      reject({
        status: LOCATION_STATUS.UNKNOWN_ERROR,
        message: '所有IP定位服务均失败',
        original: err
      });
    }
  });
} 